﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;

namespace Comarch.Animation
{
    public static class StoryboardExtensions
    {
        #region AddStoryboardsForObjects

        public static Storyboard AddStoryboardsForObjects(this Storyboard storyboard, int beginOffsetInMs, int delayBetweenObjects, Action<FrameworkElement, StoryboardBuilder> storyboardBuilderChain, params FrameworkElement[] objects)
        {
            return AddStoryboardsForObjects(storyboard, beginOffsetInMs, delayBetweenObjects, storyboardBuilderChain, (IEnumerable<UIElement>)objects);
        }

        public static Storyboard AddStoryboardsForObjects(this Storyboard storyboard, int beginOffsetInMs, int delayBetweenObjects, Action<FrameworkElement, StoryboardBuilder> storyboardBuilderChain, Panel panel)
        {
            return AddStoryboardsForObjects(storyboard, beginOffsetInMs, delayBetweenObjects, storyboardBuilderChain,(IEnumerable<UIElement>)panel.Children);
        }

        public static Storyboard AddStoryboardsForObjects(this Storyboard storyboard, int beginOffsetInMs, int delayBetweenObjects, Action<FrameworkElement, StoryboardBuilder> storyboardBuilderChain, ItemsControl itemsControl)
        {
            return AddStoryboardsForObjects(storyboard, beginOffsetInMs, delayBetweenObjects, storyboardBuilderChain, (IEnumerable<UIElement>)itemsControl.GetItemsPanel().Children);
        }

        public static Storyboard AddStoryboardsForObjects(this Storyboard storyboard, int beginOffsetInMs, int delayBetweenObjects, Action<FrameworkElement, StoryboardBuilder> storyboardBuilderChain, IEnumerable<UIElement> objects)
        {
            var i = 0;
            foreach (var element in objects)
            {
                var element1 = element;
                storyboard.AddStoryboard(beginOffsetInMs + i++ * delayBetweenObjects, (e,sbb) => storyboardBuilderChain((FrameworkElement)element1, sbb),null);
            }

            return storyboard;
        }

        #endregion 

        #region AppendStoryboardsForObjects

        public static Storyboard AppendStoryboardsForObjects(this Storyboard storyboard, int beginOffsetInMs, int delayBetweenObjects, Action<FrameworkElement, StoryboardBuilder> storyboardBuilderChain, int appendSeekTime = 0, params FrameworkElement[] objects)
        {
            return AppendStoryboardsForObjects(storyboard, beginOffsetInMs, delayBetweenObjects, storyboardBuilderChain, (IEnumerable<UIElement>)objects, appendSeekTime);
        }

        public static Storyboard AppendStoryboardsForObjects(this Storyboard storyboard, int beginOffsetInMs, int delayBetweenObjects, Action<FrameworkElement, StoryboardBuilder> storyboardBuilderChain, Panel panel, int appendSeekTime = 0)
        {
            return AppendStoryboardsForObjects(storyboard, beginOffsetInMs, delayBetweenObjects, storyboardBuilderChain, (IEnumerable<UIElement>)panel.Children,appendSeekTime);
        }

        public static Storyboard AppendStoryboardsForObjects(this Storyboard storyboard, int beginOffsetInMs, int delayBetweenObjects, Action<FrameworkElement, StoryboardBuilder> storyboardBuilderChain, ItemsControl itemsControl, int appendSeekTime = 0)
        {
            return AppendStoryboardsForObjects(storyboard, beginOffsetInMs, delayBetweenObjects, storyboardBuilderChain, (IEnumerable<UIElement>)itemsControl.GetItemsPanel().Children, appendSeekTime);
        }

        public static Storyboard AppendStoryboardsForObjects(this Storyboard storyboard, int beginOffsetInMs, int delayBetweenObjects, Action<FrameworkElement, StoryboardBuilder> storyboardBuilderChain, IEnumerable<UIElement> objects, int appendSeekTime = 0)
        {
            AddStoryboardsForObjects(storyboard, beginOffsetInMs + GetLastFrameTime(storyboard) + appendSeekTime , delayBetweenObjects, storyboardBuilderChain, objects);
            
            return storyboard;
        }

        #endregion


        public static Storyboard AppendStoryboard(this Storyboard storyboard, int beginOffsetInMs, Action<FrameworkElement, StoryboardBuilder> storyboardBuilderChain,FrameworkElement element, int appedSeekTime = 0)
        {
            return AddStoryboard(storyboard, beginOffsetInMs + GetLastFrameTime(storyboard) + appedSeekTime, storyboardBuilderChain,element);
        }

        public static Storyboard AddStoryboard(this Storyboard storyboard, int beginOffsetInMs, Action<FrameworkElement, StoryboardBuilder> storyboardBuilderChain, FrameworkElement element)
        {
            var sbb = new StoryboardBuilder();
            storyboardBuilderChain(element,sbb);
            sbb.Storyboard.BeginTime = TimeSpan.FromMilliseconds(beginOffsetInMs);
            storyboard.Children.Add(sbb.Storyboard);
            return storyboard;
        }

        private static int GetLastFrameTime(this Storyboard storyboard)
        {
            var seek = TimeSpan.Zero;
            if (storyboard.Children.Count > 0)
                seek = storyboard.Children.Max(s => ((s.BeginTime ?? TimeSpan.Zero) + s.Duration.TimeSpan));
            return (int)seek.TotalMilliseconds;
        }

        public static Storyboard OnCompletedDo(this Storyboard storyboard, Action action)
        {
            if (action != null)
                storyboard.Completed += delegate { action(); };

            return storyboard;
        }
    }
}
